home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
ada
/
gwuada_9.zip
/
INTC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-27
|
37KB
|
1,369 lines
/*
* Copyright (C) 1985-1992 New York University
*
* This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
* warranty (none) and distribution info and also the GNU General Public
* License for more details.
*/
/* continuation of interpreter procedures - part c */
/* include standard header files */
#include <stdlib.h>
#include "config.h"
#include "int.h"
#include "ivars.h"
#include "machinep.h"
#include "farithp.h"
#include "intap.h"
#include "intbp.h"
#include "intcp.h"
static int get_variable_bound(int *, int []);
void rselect(int field) /*;rselect*/
{
/*
* Perform the Ada record selection operation:
*
* Get the address of the record type template from the TOS
* Get the address of the record object from the TOS
* Get the number of the component(or field) from the instruction
* stream
*
* Check the existence of that particular component in that particular
* record(and raise CONSTRAINT_ERROR otherwise)
*
* Push the absolute address of the component on TOS. If component
* is an array, push also the address of the array type template.
* If the type of this array depends on a discriminant of the record
* a template must be dynamically built.
*/
int
type_base, type_off, record_base, record_off, field_offset,
*type_ptr, *record_ptr, *field_table_ptr, *case_table_ptr,
*case_ptr, type_type, next_case, discr_number, discr_offset,
first_field, last_field, value_discr, val_high, nb_choices,
nb_field, nb_fixed, *field_ptr, *component_ptr, *a_type_ptr,
*u_type_ptr, nb_dim, low, high, comp_off, comp_base, component_size,
object_size, template_size, *new_type_ptr, *some_ptr;
POP_ADDR(type_base, type_off);
POP_ADDR(record_base, record_off);
type_ptr = ADDR(type_base, type_off);
record_ptr = ADDR(record_base, record_off);
type_type = TYPE(type_ptr);
/* constrained record subtype */
if (type_type == TT_C_RECORD) { /* find base type */
type_base = C_RECORD(type_ptr)->cbase;
type_off = C_RECORD(type_ptr)->coff;
type_ptr = ADDR(type_base, type_off);
type_type = TYPE(type_ptr);
}
else if (type_type == TT_D_RECORD) {
type_base = D_TYPE(type_ptr)->dbase;
type_off = D_TYPE(type_ptr)->doff;
type_ptr = ADDR(type_base, type_off);
type_type = TYPE(type_ptr);
}
else if (type_type == TT_RECORD) {
field_table_ptr = type_ptr + WORDS_RECORD;
nb_fixed = RECORD(type_ptr)->nb_field;
}
if (type_type == TT_U_RECORD || type_type == TT_V_RECORD) {
nb_fixed = U_RECORD(type_ptr)->nb_fixed_u;
nb_field = U_RECORD(type_ptr)->nb_field_u;
field_table_ptr = type_ptr + WORDS_U_RECORD;
case_table_ptr = field_table_ptr + 3 * nb_field;
}
/* The result is simple to obtain... unless the record has varying size */
if (type_type == TT_V_RECORD) {
field_offset = 0;
first_field = 0;
last_field = nb_fixed - 1;
next_case = U_RECORD(type_ptr)->first_case;
nb_discr = U_RECORD(type_ptr)->nb_discr_u;
for (i = 0; i < nb_discr; i++)
discr_list[i] = *(record_ptr + i);
for (;;) {
field_ptr = 3 * first_field + field_table_ptr;
for (i = first_field; i <= MIN((field - 1), last_field); i++) {
/* accumulate size of components */
component_ptr = ADDR(*(field_ptr + 1), *(field_ptr + 2));
field_offset += actual_size(component_ptr, discr_list);
field_ptr += 3;
}
if (field >= first_field && field <= last_field) {
break;
}
else if (field < first_field
||(field > last_field && next_case == -1)) {
raise(CONSTRAINT_ERROR, "Record component not present");
return;
}
/* We have : field > last_field and next_case /= -1 */
case_ptr = case_table_ptr + next_case;
discr_number = *case_ptr++;
discr_offset = *(field_table_ptr + 3 * discr_number);
value_discr = *(record_ptr + discr_offset);
nb_choices = *case_ptr;
case_ptr += 4;
val_high = *case_ptr;
for (i = 2; i <= nb_choices; i++) {
if (val_high > value_discr)
break;
case_ptr += 4;
val_high = *case_ptr;
}
next_case = *--case_ptr;
last_field = *--case_ptr;
first_field = *--case_ptr;
}
field_ptr = field_table_ptr + 3 * field;
}
/* Record is not varying */
else {
field_ptr = field_table_ptr + 3 * field;
field_offset = *field_ptr;
}
PUSH_ADDR(record_base, field_offset + record_off);
/* check if component is an array */
type_base = *(field_ptr + 1);
type_off = *(field_ptr + 2);
type_type = TYPE(ADDR(type_base, type_off));
if ( type_type == TT_S_ARRAY
|| type_type == TT_U_ARRAY
|| type_type == TT_C_ARRAY
|| type_type == TT_D_ARRAY) {
if (type_type == TT_D_ARRAY) {
/* must build a type template */
/* necessarily the record is a TT_V_RECORD or a TT_U_RECORD with */
/* default values for the discriminants */
nb_discr = U_RECORD(type_ptr)->nb_discr_u;
for (i = 0; i < nb_discr; i++)
discr_list[i] = *(record_ptr + i);
a_type_ptr = ADDR(type_base, type_off);
nb_dim = D_TYPE(a_type_ptr)->nb_discr_d;
type_base = D_TYPE(a_type_ptr)->dbase;
type_off = D_TYPE(a_type_ptr)->doff;
u_type_ptr = ADDR(type_base, type_off);
a_type_ptr += WORDS_D_TYPE;/* =bounds */
type_type = *u_type_ptr;
if (nb_dim == 1) {
/* unidimensional case: we build an s_array */
low = get_variable_bound(a_type_ptr, discr_list);
a_type_ptr += 2;
high = get_variable_bound(a_type_ptr, discr_list);
if (type_type == TT_S_ARRAY) {
component_size = S_ARRAY(u_type_ptr)->component_size;
}
else {
comp_base = ARRAY(u_type_ptr)->component_base;
comp_off = ARRAY(u_type_ptr)->component_offset;
component_size = SIZE(ADDR(comp_base, comp_off));
}
object_size = component_size *(high - low + 1);
if (object_size < 0)
object_size = 0;
create(WORDS_S_ARRAY, &type_base, &type_off, &new_type_ptr);
S_ARRAY(new_type_ptr)->ttype = TT_S_ARRAY;
S_ARRAY(new_type_ptr)->object_size = object_size;
S_ARRAY(new_type_ptr)->component_size = component_size;
S_ARRAY(new_type_ptr)->index_size = 1;
S_ARRAY(new_type_ptr)->salow = low;
S_ARRAY(new_type_ptr)->sahigh = high;
}
else { /* nb_dim > 1 */
template_size = 2 *(nb_dim - 1) + WORDS_ARRAY;
create(template_size, &type_base, &type_off, &new_type_ptr);
ARRAY(new_type_ptr)->ttype = TT_C_ARRAY;
ARRAY(new_type_ptr)->dim = nb_dim;
comp_base = ARRAY(u_type_ptr)->component_base;
comp_off = ARRAY(u_type_ptr)->component_offset;
ARRAY(new_type_ptr)->component_base = comp_base;
ARRAY(new_type_ptr)->component_offset = comp_off;
component_size = SIZE(ADDR(comp_base, comp_off));
/* Beware: indices in reverse order */
some_ptr = new_type_ptr + WORDS_ARRAY + 2 * nb_dim - 3;
for (i = 1; i <= nb_dim; i++) {
low = get_variable_bound(a_type_ptr, discr_list);
a_type_ptr += 2;
high = get_variable_bound(a_type_ptr, discr_list);
a_type_ptr += 2;
create(WORDS_I_RANGE, &bas2, &off2, &ptr2);
TYPE(ptr2) = TT_I_RANGE;
SIZE(ptr2) = 1;
I_RANGE(ptr2)->ilow = low;
I_RANGE(ptr2)->ihigh = high;
*some_ptr-- = off2;
*some_ptr-- = bas2;
if (high >= low)
component_size *= (high - low + 1);
else
component_size = 0;
}
SIZE(new_type_ptr) = component_size;
}
}
PUSH_ADDR(type_base, type_off);
}
/* no check to perform if done already for varying size records */
if (type_type == TT_V_RECORD)
return;
first_field = 0;
last_field = nb_fixed - 1;
next_case = U_RECORD(type_ptr)->first_case;
for (;;) {
if ((field >= first_field) &&(field <= last_field)) {
return;
}
else if (field < first_field
||(field > last_field && next_case == -1)) {
raise(CONSTRAINT_ERROR, "Record component not present");
return;
}
/* then we have : field > last_field and next_case /= -1 */
case_ptr = case_table_ptr + next_case;
discr_number = *case_ptr++;
discr_offset = *(field_table_ptr + 3 * discr_number);
value_discr = *(record_ptr + discr_offset);
nb_choices = *case_ptr;
case_ptr += 4;
val_high = *case_ptr;
for (i = 2; i <= nb_choices; i++) {
if (val_high > value_discr) {
break